package com.ferryc.commons.scan;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.ferryc.commons.annotation.SystemLog;
import com.ferryc.commons.utils.CommonUtil;
import com.ferryc.commons.utils.StringUtil;
import com.ferryc.commons.web.BaseController;
import com.ferryc.commons.web.JsonResponse;

/**
 * 
 * <pre>
 * 【类型】: LogAopAction <br/> 
 * 【作用】: 日志 切点类 . <br/>  
 * 【时间】：2017年5月23日 上午9:43:20 <br/> 
 * 【作者】：Ferry Chen <br/>
 * </pre>
 */
@Aspect
@Component
public class LogAopAction extends BaseController {

	/** */
	private static final String MODULE = "module";
	/** */
	private static final String METHODS = "methods";
	/** */
	private static final String NEVER_USER_INFO = "无法获取登录用户信息！";

	/**
	 * 
	 * 【方法名】 : Controller层切点. <br/>
	 * 【作者】: Ferry Chen .<br/>
	 * 【时间】： 2017年5月23日 上午9:43:50 .<br/>
	 * 【参数】： .<br/>
	 * .<br/>
	 */
	@Pointcut("@annotation(com.ferryc.commons.annotation.SystemLog)")
	public void controllerAspect() {
	}

	/**
	 * 
	 * 【方法名】 :操作异常记录 . <br/>
	 * 【作者】: Ferry Chen .<br/>
	 * 【时间】： 2017年5月23日 上午9:44:21 .<br/>
	 * 【参数】： .<br/>
	 * 
	 * @param point
	 *            JoinPoint
	 * @param e
	 *            Throwable
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint point, Throwable e) throws Throwable {
		HttpServletRequest request = CommonUtil.getHttpRequest();
		Map<String, Object> map = getControllerMethodDescription(point);
		LogUtils.saveLog(request, null, (Exception) e, String.valueOf(map.get(MODULE)) + "-" + String.valueOf(map.get(METHODS)), null);
	}

	/**
	 * 
	 * 【方法名】 : 前置通知 用于拦截Controller层记录用户的操作. <br/>
	 * 【注意】: (这里描述这个方法的注意事项 – 可选).<br/>
	 * 【作者】: Ferry Chen .<br/>
	 * 【时间】： 2017年5月23日 上午9:44:45 .<br/>
	 * 【参数】： .<br/>
	 * 
	 * @param point
	 *            ProceedingJoinPoint
	 * @return .<br/>
	 * @throws Throwable
	 */
	@Around("controllerAspect()")
	public Object doController(ProceedingJoinPoint point) throws Throwable {
		HttpServletRequest request = CommonUtil.getHttpRequest();
		Map<String, Object> map = getControllerMethodDescription(point);
		Object result = point.proceed();
		JsonResponse r = null;
		if (result instanceof JsonResponse) {
			r = (JsonResponse) result;
		}
		LogUtils.saveLog(request, null, null, String.valueOf(map.get(MODULE)) + "-" + String.valueOf(map.get(METHODS)), r != null ? r.getMsg() : null);
		return result;
	}

	/**
	 * 
	 * 【方法名】 : 获取注解中对方法的描述信息 用于Controller层注解. <br/>
	 * 【作者】: Ferry Chen .<br/>
	 * 【时间】： 2017年5月23日 上午9:45:01 .<br/>
	 * 【参数】： .<br/>
	 * 
	 * @param joinPoint
	 *            JoinPoint
	 * @return Map
	 * @throws Exception .<br/>
	 */
	@SuppressWarnings("rawtypes")
	public Map<String, Object> getControllerMethodDescription(JoinPoint joinPoint) throws ClassNotFoundException {
		Map<String, Object> map = new HashMap();
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					map.put(MODULE, method.getAnnotation(SystemLog.class).module());
					map.put(METHODS, method.getAnnotation(SystemLog.class).methods());
					String de = method.getAnnotation(SystemLog.class).description();
					de = StringUtil.isEmpty(de) ? "执行成功!" : de;
					map.put("description", de);
					break;
				}
			}
		}
		return map;
	}

}
